<template>
  <div class="video-page">
    <div class="left-section">
      <a-typography-title
        class="video-title"
        :level="3"
      >
        {{ video.title }}
      </a-typography-title>

      <div class="metadata">
        <span class="video-data">
          <PlayCircleOutlined />
          {{ formatNumber(video.viewCount) }}
        </span>
        <span class="video-data">
          <clock-circle-outlined />
          {{ timeFormat(video.publishTime) }}
        </span>
      </div>

      <div
        ref="playerContainer"
        class="video-player"
      />

      <!-- 点赞、踩、举报 -->
      <div class="video-function">
        <!-- 点赞 -->
        <div
          class="video-function-item"
          :style="isLikeClick && `color: #1890ff`"
          @click="handleLikeClick"
        >
          <LikeOutlined />
          <span class="text">{{ formatNumber(likeCount) }}</span>
        </div>

        <div class="divider"></div>

        <!-- 踩 -->
        <div
          class="video-function-item"
          :style="isDislikeClick && `color: #1890ff`"
          @click="handleDislikeClick"
        >
          <DislikeOutlined />
          <span class="text">{{ formatNumber(dislikeCount) }}</span>
        </div>

        <div class="divider"></div>

        <!-- 踩 -->
        <div
          class="video-function-item"
          :style="isFavourite && `color: #1890ff`"
          @click="handleFavouriteClick"
        >
          <HeartOutlined />
          <span class="text">收藏</span>
        </div>

        <div class="divider"></div>

        <!-- 举报 -->
        <div
          class="video-function-item"
          @click="openReportDialog"
        >
          <InfoCircleOutlined />
          <span class="text">举报</span>
        </div>
      </div>

      <a-divider />

      <div class="description">
        <a-collapse
          v-model:activeKey="activeDescriptionKeys"
          ghost
        >
          <a-collapse-panel
            header="视频简介"
            key="1"
          >
            <p>{{ video.description }}</p>
          </a-collapse-panel>
        </a-collapse>
      </div>

      <div class="tags">
        <div class="tags-container">
          <a-button
            v-for="(label, index) in video.labelList"
            :key="index"
            shape="round"
            size="small"
          >
            #{{ label.labelName }}
          </a-button>
        </div>
      </div>

      <Comment
        v-model:videoId="video.id"
        v-model:commentCount="video.commentCount"
      />
    </div>

    <div class="right-section">
      <div class="author-info">
        <img
          :src="video.avatarUrl"
          alt="用户头像"
          class="avatar"
          @click="locateToUserProfile(video.userId)"
        />
        <div class="author-details">
          <div class="name-message">
            <p
              class="name"
              @click="locateToUserProfile(video.userId)"
            >
              {{ video.nickname }}
            </p>

            <a-button
              v-if="userStore.getUserId !== video.userId"
              type="link"
              @click="locateToSendMessage"
              class="message-btn"
            >
              <template #icon>
                <message-outlined />
              </template>
              发消息
            </a-button>
          </div>

          <p
            class="signature"
            :title="video.signature"
          >
            {{ video.signature }}
          </p>

          <a-button
            v-if="userStore.getUserId !== video.userId"
            type="primary"
            block
            @click="subscribe"
            size="middle"
            @mouseenter="handleSubscribeMouseenter"
            @mouseleave="handleSubscribeMouseleave"
          >
            {{ subscribeText }}
          </a-button>
        </div>
      </div>

      <div
        class="video-collection"
        v-if="collectionRefList?.length > 0"
      >
        <a-typography-title
          class="video-collection-title"
          :level="4"
        >
          视频合集
        </a-typography-title>

        <div class="video-collection-content">
          <a-button
            type="link"
            class="video-collection-item"
            v-for="item in collectionRefList"
            @click="locateToVideo(item.videoId)"
            :style="item.videoId == video?.id && 'background: #1890ff; color: #fff'"
          >
            {{ item.sorted }}
          </a-button>
        </div>
      </div>

      <div class="recommendations">
        <a-typography-title
          class="recommendations-title"
          :level="4"
        >
          相关推荐
        </a-typography-title>
        <div
          v-for="(item, index) in recommendations"
          :key="index"
          class="recommendation"
        >
          <img
            :src="item.thumbnailUrl"
            alt="视频封面"
            class="thumbnail"
            @click="locateToVideo(item.id)"
          />
          <div class="recommendation-details">
            <a-button
              type="link"
              class="title-btn"
              @click="locateToVideo(item.id)"
            >
              {{ item.title }}
            </a-button>

            <a-button
              type="link"
              class="author-btn"
              @click="locateToUserProfile(item.userId)"
            >
              {{ item.nickname }}
            </a-button>

            <div class="stats">
              <span class="stats-data">
                <PlayCircleOutlined />
                {{ formatNumber(item.viewCount) }}
              </span>

              <span class="stats-data">
                <ClockCircleOutlined />
                {{ dateFormat(item.publishTime) }}
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <teleport to="body">
    <!-- 举报对话框 -->
    <a-modal
      v-model:visible="reportModalVisible"
      title="举报内容"
      ok-text="提交"
      cancel-text="取消"
      @ok="submitReport"
      @cancel="closeReportDialog"
      :zIndex="1050"
      :centered="true"
      :keyboard="false"
      :mask-closable="false"
    >
      <a-checkbox-group
        v-model:value="selectedReasons"
        style="width: 100%"
      >
        <a-row :gutter="[16, 16]">
          <a-col
            :span="12"
            v-for="reason in reportOptions"
          >
            <a-checkbox :value="reason.label">{{ reason.label }}</a-checkbox>
          </a-col>
          <a-col :span="12">
            <a-checkbox value="other">其他</a-checkbox>
          </a-col>
        </a-row>
      </a-checkbox-group>
      <div
        v-if="selectedReasons.includes('other')"
        style="margin: 10px 0 40px 0"
      >
        <a-textarea
          v-model:value="otherReasonText"
          placeholder="请输入具体原因..."
          :rows="4"
          :maxlength="500"
          show-count
          style="resize: none"
        />
      </div>
    </a-modal>
  </teleport>
</template>

<script setup lang="ts">
import {
  PlayCircleOutlined,
  ClockCircleOutlined,
  MessageOutlined,
  LikeOutlined,
  DislikeOutlined,
  HeartOutlined,
  InfoCircleOutlined
} from '@ant-design/icons-vue'
import Comment from './components/comment/index.vue'
import type { CvVideoDetailRespVO } from '@/types/video'
import Player from 'xgplayer'
import 'xgplayer/dist/index.min.css'
import HlsJsPlayer from 'xgplayer-hls'
import dayjs from 'dayjs'
import { getVideoDetail, getVideoRecommend } from '@/api/video'
import { getVideoHistory, saveVideoHistoryRecord } from '@/api/history'
import type { CvVideoDetailHistoryRespVO, CvVideoHistorySaveReqVO } from '@/types/history'
import { reportOptions, reportType, videoPlayStatus } from '@/utils/options'
import { getAccessToken } from '@/utils/auth'
import { cancelLike, getLikeCount, getLikeStatus, saveLike } from '@/api/video/like'
import { message } from 'ant-design-vue'
import type { CvVideoItemRespVO } from '@/types/global'
import { IPlayerOptions } from 'xgplayer/es/player'
import { cancelDislike, getDislikeCount, getDislikeStatus, saveDislike } from '@/api/video/dislike'
import { cancelSubscribe, getSubscribe, saveSubscribe } from '@/api/subscribe'
import type { CvSubscribeDetailRespVO, CvSubscribeSaveReqVO } from '@/types/subscribe'
import { useUserStore } from '@/store/modules/user'
import { cancelFavourite, getVideoIsFavourite, saveFavourite } from '@/api/favourite'
import type { CvVideoFavouriteSaveReqVO } from '@/types/favourite'
import { CvVideoCollectionRefRespVO } from '@/types/collectionRef'
import { getVideoIdListByCollectionId } from '@/api/collectionRef'
import { CvReportSaveReqVO } from '@/types/report'
import { saveReport } from '@/api/report'

const route = useRoute()
const router = useRouter()

const userStore = useUserStore()

/**
 * 视频播放器
 */
const playerContainer = ref(null)
let player = null

/**
 * 视频详情
 */
const video = ref<CvVideoDetailRespVO>(<CvVideoDetailRespVO>{
  videoId: 0,
  userId: 0,
  nickname: '',
  avatar: 0,
  avatarUrl: '',
  signature: '',
  title: '',
  viewCount: 0,
  commentCount: 0,
  thumbnail: 0,
  thumbnailUrl: '',
  resource720p: '',
  resource1080p: '',
  description: '',
  labelList: [],
  publishTime: ''
})

/**
 * 历史记录
 */
const historyRecord = ref<CvVideoDetailHistoryRespVO>(<CvVideoDetailHistoryRespVO>{
  id: 0,
  userId: 0,
  videoId: 0,
  position: 0,
  duration: 0,
  startTime: '',
  endTime: ''
})

/**
 * 视频点赞和踩数量
 */
const likeCount = ref(0)
const isLikeClick = ref(false)
const dislikeCount = ref(0)
const isDislikeClick = ref(false)

/**
 * 收藏状态
 */
const isFavourite = ref(false)
const favText = ref('收藏')

/**
 * 视频简介
 */
const activeDescriptionKeys = ref<string[]>(['1'])

/**
 * 订阅状态
 */
const subscribeDetail = ref<CvSubscribeDetailRespVO>()
const subscribeText = ref('关注')
const isSubscribed = ref(false)

/**
 * 视频推荐列表
 */
const recommendations = ref<CvVideoItemRespVO[]>([])

onMounted(async () => {
  if (!route.query.videoId || isNaN(Number(route.query.videoId))) {
    await router.push({ path: '/404' })
    return
  }

  video.value = await getVideoDetail(route.query.videoId as string)

  if (!video.value) {
    await router.push({ path: '/404' })
    return
  }

  // 获取合集数据
  await getCollectionRefList(video.value.id)

  // 获取推荐列表
  recommendations.value = await getVideoRecommend(video.value.id)

  likeCount.value = await getLikeCount(video.value.id)
  dislikeCount.value = await getDislikeCount(video.value.id)

  if (playerContainer.value && video.value?.resource720p && video.value?.resource1080p) {
    player = new Player(<IPlayerOptions>{
      el: playerContainer.value,
      url: video.value.resource720p,
      controls: true,
      fluid: true,
      lang: 'zh-cn',
      volume: 0.6,
      pip: true,
      autoplay: false,
      plugins: [HlsJsPlayer]
    })

    player.emit('resourceReady', [
      {
        url: video.value?.resource720p,
        definition: '高清 720p'
      },
      {
        url: video.value?.resource1080p,
        definition: '超清 1080p'
      }
    ])
  }

  if (video.value?.thumbnailUrl) {
    player.poster = video.value?.thumbnailUrl
  }

  if (getAccessToken()) {
    isLikeClick.value = await getLikeStatus(video.value.id)
    isDislikeClick.value = await getDislikeStatus(video.value.id)

    historyRecord.value = await getVideoHistory(video.value.id)

    if (
      historyRecord.value?.position &&
      historyRecord.value?.playStatus !== videoPlayStatus[2].value
    ) {
      player.seek(historyRecord.value.position)
    }

    subscribeDetail.value = await getSubscribe(video.value.userId)
    if (subscribeDetail.value) {
      isSubscribed.value = true
      subscribeText.value = '已关注'
    }

    isFavourite.value = await getVideoIsFavourite(video.value.id)
    if (isFavourite.value) {
      favText.value = '已收藏'
    }
  }

  window.addEventListener('beforeunload', storeVideoHistory)
})

onBeforeUnmount(async () => {
  await storeVideoHistory()
  player?.destroy()

  window.removeEventListener('beforeunload', storeVideoHistory)
})

/**
 * 存储历史记录
 */
const storeVideoHistory = async () => {
  // 保存播放记录
  if (getAccessToken() && video.value.id) {
    let saveReq = <CvVideoHistorySaveReqVO>{
      id:
        historyRecord.value?.id && historyRecord.value?.id !== 0
          ? historyRecord.value.id
          : undefined,
      videoId: video.value.id,
      startTime: historyRecord.value?.startTime || new Date().getTime(),
      endTime: new Date().getTime(),
      position: player?.currentTime || 0,
      duration: player?.duration || 0
    }

    if (player?.ended) {
      saveReq.playStatus = videoPlayStatus[2].value
    } else if (player?.paused) {
      saveReq.playStatus = videoPlayStatus[1].value
    } else {
      saveReq.playStatus = videoPlayStatus[0].value
    }

    await saveVideoHistoryRecord(saveReq)
    historyRecord.value = await getVideoHistory(video.value.id)
  }
}

/**
 * 播放量格式化
 */
const formatNumber = (num: number) => {
  if (!num) {
    return 0
  }

  if (num >= 1000 && num < 10000) {
    return (num / 1000).toFixed(1) + 'K'
  } else if (num >= 10000) {
    return (num / 10000).toFixed(1) + 'W'
  } else {
    return num.toString()
  }
}

/**
 * 时间格式化
 */
const timeFormat = (time: string) => {
  if (time) {
    return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
  }
  return ''
}

/**
 * 日期格式化
 */
const dateFormat = (time: string) => {
  if (time) {
    return dayjs(time).format('YYYY-MM-DD')
  }
  return ''
}

/**
 * 视频点赞/取消点赞
 */
const handleLikeClick = () => {
  if (!getAccessToken()) {
    message.error('请登录')
    return
  }

  if (isLikeClick.value) {
    cancelLike(video.value.id)
      .then(() => {
        isLikeClick.value = false
        likeCount.value--
      })
      .catch(() => {
        message.error('取消点赞失败')
      })
  } else {
    if (isDislikeClick.value) {
      handleDislikeClick()
    }

    saveLike(video.value.id)
      .then(() => {
        isLikeClick.value = true
        likeCount.value++
      })
      .catch(() => {})
  }
}

/**
 * 视频踩/取消踩
 */
const handleDislikeClick = () => {
  if (!getAccessToken()) {
    message.error('请登录')
    return
  }

  if (isDislikeClick.value) {
    cancelDislike(video.value.id)
      .then(() => {
        isDislikeClick.value = false
        dislikeCount.value--
      })
      .catch(() => {
        message.error('取消踩失败')
      })
  } else {
    if (isLikeClick.value) {
      handleLikeClick()
    }

    saveDislike(video.value.id)
      .then(() => {
        isDislikeClick.value = true
        dislikeCount.value++
      })
      .catch(() => {})
  }
}

/**
 * 收藏/取消收藏
 */
const handleFavouriteClick = async () => {
  if (!getAccessToken()) {
    message.error('请登录')
    return
  }

  if (isFavourite.value) {
    await cancelFavourite(video.value.id)
    isFavourite.value = false
    favText.value = '收藏'
    message.success('取消收藏成功')
  } else {
    let data = <CvVideoFavouriteSaveReqVO>{
      videoId: video.value.id
    }
    await saveFavourite(data)
    isFavourite.value = true
    favText.value = '已收藏'
    message.success('收藏成功')
  }
}

/**
 * 视频合集
 */
const collectionRefList = ref<CvVideoCollectionRefRespVO[]>()

const getCollectionRefList = async (videoId: number) => {
  collectionRefList.value = await getVideoIdListByCollectionId(videoId)
}

/**
 * 跳转至用户主页
 */
const locateToUserProfile = (userId: number) => {
  storeVideoHistory()
  window.open(`/profile?userId=${userId}`)
}

/**
 * 跳转至发送私信页
 */
const locateToSendMessage = () => {
  if (!getAccessToken()) {
    message.error('请登录')
    return
  }
  storeVideoHistory()
  router.push({ path: '/message', query: { userId: video.value.userId } })
}

/**
 * 订阅
 */
const subscribe = async () => {
  if (!getAccessToken()) {
    message.error('请登录')
    return
  }

  if (isSubscribed.value) {
    // 取消订阅
    await cancelSubscribe(subscribeDetail.value?.id as number)
    subscribeText.value = '关注'
    isSubscribed.value = false
    message.success('取关成功')
  } else {
    // 订阅
    await saveSubscribe(<CvSubscribeSaveReqVO>{
      targetUserId: video.value.userId
    })
    subscribeDetail.value = await getSubscribe(video.value.userId)
    subscribeText.value = '已关注'
    isSubscribed.value = true
    message.success('关注成功')
  }
}

/**
 * 订阅按钮进入事件
 */
const handleSubscribeMouseenter = () => {
  if (isSubscribed.value) {
    subscribeText.value = '取消关注'
  } else {
    subscribeText.value = '关注'
  }
}

/**
 * 订阅按钮离开事件
 */
const handleSubscribeMouseleave = () => {
  if (!isSubscribed.value) {
    subscribeText.value = '关注'
  } else {
    subscribeText.value = '已关注'
  }
}

/**
 * 跳转至视频详情页
 */
const locateToVideo = (videoId: number) => {
  if (video.value.id && video.value.id == videoId) {
    return
  }
  window.open(`/video?videoId=${videoId}`)
}

// ==================== 举报视频 ====================

const reportModalVisible = ref(false)
const selectedReasons = ref<string[]>([])
const otherReasonText = ref('')

const openReportDialog = () => {
  if (!getAccessToken()) {
    message.error('请登录')
    return
  }

  if (userStore.getUserId == video.value.userId) {
    message.error('你不能举报自己的视频')
    return
  }

  reportModalVisible.value = true
  selectedReasons.value = []
  otherReasonText.value = ''
}

const submitReport = async () => {
  if (video.value.id) {
    let reasons = ''
    for (let i = 0; i < selectedReasons.value.length; i++) {
      if (selectedReasons.value[i] !== 'other') {
        reasons = reasons + (i + 1) + '. ' + selectedReasons.value[i] + '\n'
      } else if (otherReasonText.value) {
        reasons = reasons + selectedReasons.value.length + '. ' + otherReasonText.value
      }
    }

    if (!reasons) {
      message.error('请选择举报理由')
      return
    }

    await saveReport(<CvReportSaveReqVO>{
      id: null,
      reason: reasons,
      reportType: reportType[0].value,
      reportUserId: userStore.getUserId,
      targetUserId: video.value.userId,
      childrenId: video.value.id
    })
    message.success('举报成功，请待客服审核处理')
    closeReportDialog()
  }
}

const closeReportDialog = () => {
  reportModalVisible.value = false
  selectedReasons.value = []
  otherReasonText.value = ''
}
</script>

<style scoped>
/* 左边部分 */
.video-page {
  display: flex;
  justify-content: space-between;
  padding: 20px;
}

.left-section {
  width: 65%;
  margin-right: 5%;
}

.video-title {
  margin-bottom: 10px;
}

.metadata {
  color: #999;
  font-size: 14px;
  margin-bottom: 10px;
  cursor: default;
}

.metadata .video-data {
  margin-right: 10px;
}

.video-player {
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  width: 100%;
}

.description {
  margin-top: 20px;
}

:deep(.ant-collapse-header-text) {
  font-size: 16px;
  color: #999;
  font-weight: bold !important;
}

.tags {
  margin: 20px 0;
}

.tags-container {
  display: flex;
  flex-wrap: wrap;
  transition: max-height 0.3s ease-in-out;
  gap: 10px;
}

/* 右边部分 */
.right-section {
  width: 30%;
}

.author-info {
  display: flex;
  align-items: flex-start;
  margin-bottom: 20px;
}

.avatar {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  margin-right: 10px;
  cursor: pointer;
}

.author-details {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
}

.author-details .name-message {
  display: flex;
  align-items: center;
  width: 100%;
}

.author-details .name {
  font-size: 16px;
  color: #333;
  margin: 0 10px 0 0;
  cursor: pointer;
}

.author-details .name:hover {
  color: #1890ff;
}

.author-details .signature {
  font-size: 14px;
  color: #999;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 250px;
}

.author-details .message-btn {
  font-size: 14px;
  color: #999;
  padding: 0;
}

.author-details .message-btn:hover {
  color: #1890ff;
}

.video-collection-content {
  margin-bottom: 20px;
  background: rgba(0, 0, 0, 0.05);
  padding: 20px;
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
  max-height: 400px;
  overflow-y: auto;
}

.video-collection-item {
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.1);
}

.recommendations .recommendations-title {
  margin-top: 20px;
  margin-bottom: 10px;
}

.recommendations .recommendation {
  display: flex;
  align-items: flex-start;
  margin-bottom: 10px;
  cursor: pointer;
}

.recommendations .thumbnail {
  width: 150px;
  height: 84px;
  border-radius: 8px;
  object-fit: cover;
  margin-right: 10px;
}

.recommendations .recommendation-details {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: calc(100% - 160px);
}

.recommendations .recommendation-details .title-btn {
  color: #333;
  padding: 0;
  cursor: pointer;
  font-size: 16px;
  font-weight: bold;
}

.recommendations .recommendation-details .author-btn {
  color: #999;
  padding: 0;
  cursor: pointer;
  font-size: 14px;
}

.recommendations .recommendation-details .title-btn:hover,
.recommendations .recommendation-details .author-btn:hover {
  color: #1890ff;
}

.recommendations .recommendation-details .stats {
  display: flex;
  align-items: center;
  font-size: 14px;
  color: #999;
  gap: 10px;
  cursor: default;
}

.video-function {
  margin-top: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px;
  border: 1px solid #e7e7e7;
}

.video-function-item {
  font-size: 16px;
  display: flex;
  gap: 10px;
  width: 33%;
  justify-content: center;
  align-items: center;
  cursor: pointer;
}

.video-function-item:hover {
  color: #1890ff;
}

.divider {
  width: 1px;
  height: 30px;
  background-color: #e5e6e8;
  margin: 0 15px;
}
</style>
